﻿namespace EasyWeb.Data.EntityFramework
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Threading.Tasks;
    using EasyWeb.Configuration;
    using EasyWeb.Data.EntityFramework.Models;

    [Export(typeof(IEWConfigurationDao))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class EWConfigurationDao : EWDao, IEWConfigurationDao
    {
        public virtual async Task<T> SelectAsync<T>()
            where T : class
        {
            using (var transaction = EWHelpers.Data.BeginTransaction())
            {
                var result = default(object);

                if (typeof(T) == typeof(EWDefaultLanguageConfiguration))
                {
                    result = await SelectCoreAsync<EWDefaultLanguageConfiguration, EWConfigurationModel>(
                        EWCommon.ConfigurationIdDefaultLanguage,
                        converter: EWModelHelpers.Configuration.DefaultLanguage.ToDomain);
                }
                else if (typeof(T) == typeof(EWSystemPrefixConfiguration))
                {
                    result = await SelectCoreAsync<EWSystemPrefixConfiguration, EWConfigurationModel>(
                        EWCommon.ConfigurationIdSystemPrefix,
                        converter: EWModelHelpers.Configuration.SystemPrefix.ToDomain);
                }
                else
                {
                    throw new NotSupportedException(string.Format("The type '{0}' is not supported.", typeof(T)));
                }

                transaction.Complete();

                return (T)result;
            }
        }

        public virtual Task CreateAsync<T>(T domain)
            where T : class
        {
            throw new NotSupportedException();
        }

        public virtual async Task UpdateAsync<T>(T domain)
            where T : class
        {
            EWGuard.IsNotNull(domain, "domain");

            using (var transaction = EWHelpers.Data.BeginTransaction())
            {
                var obj = (object)domain;

                if (typeof(T) == typeof(EWDefaultLanguageConfiguration))
                {
                    await UpdateCoreAsync<EWDefaultLanguageConfiguration, EWConfigurationModel>(
                        (EWDefaultLanguageConfiguration)obj,
                        converter: EWModelHelpers.Configuration.DefaultLanguage.ToEntity);
                }
                else if (typeof(T) == typeof(EWSystemPrefixConfiguration))
                {
                    await UpdateCoreAsync<EWSystemPrefixConfiguration, EWConfigurationModel>(
                        (EWSystemPrefixConfiguration)obj,
                        converter: EWModelHelpers.Configuration.SystemPrefix.ToEntity);
                }
                else
                {
                    throw new NotSupportedException(string.Format("The type '{0}' is not supported.", typeof(T)));
                }

                transaction.Complete();
            }
        }

        public virtual Task DeleteAsync(Guid id, byte[] timestamp)
        {
            throw new NotSupportedException();
        }

        // used by update
        internal override void DefaultDomainInitializer<TDomain>(TDomain domain, Tuple<DateTime, string, byte[]> parameters)
        {
            dynamic proxy = domain;
            proxy.Timestamp = parameters.Item3;
        }

        // used by create
        internal override void DefaultDomainInitializer<TDomain>(TDomain domain, Tuple<Guid, DateTime, string, byte[]> parameters)
        {
            dynamic proxy = domain;
            proxy.Id = parameters.Item1;
            proxy.Timestamp = parameters.Item4;
        }

        // used by update
        internal override void DefaultEntityInitializer<TEntity>(TEntity entity, Tuple<DateTime, string> parameters)
        {
            base.DefaultEntityInitializer(entity, parameters);
            // set following properties due to avoid entity validation error
            dynamic proxy = entity;
            proxy.Created = parameters.Item1;
            proxy.CreatedBy = parameters.Item2;
        }
    }
}
